/**
 * minizinccodegenerator.h is part of cbs-framework.
 *
 * cbs-framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * cbs-framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with cbs-framework.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef MINIZINCCODEGENERATOR_H
#define MINIZINCCODEGENERATOR_H

#include "../../utils/visitor/visitor.h"
#include "../../utils/printable.h"
#include "../definitions.h"
#include <sstream>
#include <vector>

// Forward declarations
class Model;
class TaskTimeWindowConstraint;
class ResourceCapacityConstraint;
class TaskLenghtConstraint;
class Task;
class Resource;

typedef std::vector< std::string >              tStringVector;
typedef std::vector< tCapacity >                tCapacityVector;
typedef std::vector< tTime >                    tTimeVector;
typedef std::vector< tNeededResources >         tNeededResourcesVector;
typedef std::pair < std::size_t, std::size_t >  tPrecedence;
typedef std::vector< tPrecedence >              tPrecedencesVector;

class MiniZincCodeGenerator : public Visitor, public Printable
{
public:

    MiniZincCodeGenerator();

    virtual ~MiniZincCodeGenerator();

    virtual std::string Print() const;

    void Reset();

    // visit model.
    virtual void Visit( Model * a_model );

    // Visit constraints.
    virtual void Visit( TaskTimeWindowConstraint * a_constraint );
    virtual void Visit( TaskLenghtConstraint * a_constraint );
    virtual void Visit( TaskResourcesNeededConstraint * a_constraint );

    virtual void Visit( ResourceCapacityConstraint * a_constraint );

    virtual void Visit( ModelAllowIdlesConstraint * a_constraint );
    virtual void Visit( ModelMaxTimeConstraint * a_constraint );
    virtual void Visit( ModelPrecedenceConstraint * a_constraint );

    // Visit tasks and resources.
    virtual void Visit( Task * a_task );
    virtual void Visit( Resource * a_resource );

private:

    // Fields.
    // -------

    std::ostringstream m_strStream;

    tTime                   m_maxTime;
    unsigned short          m_nTasks;
    unsigned short          m_nResources;
    tTimeVector             m_lenghts;
    tNeededResourcesVector  m_resources;
    tCapacityVector         m_capacities;
    tTimeVector             m_start_times_windows;
    tTimeVector             m_end_times_windows;
    std::string             m_modelName;
    bool                    m_allowIdle;
    tStringVector           m_tasksNames;
    tStringVector           m_resourcesNames;
    tPrecedencesVector      m_precedences;

    static const std::string N_TASKS;
    static const std::string N_RESOURCES;
    static const std::string CAPACITY;
    static const std::string RESOURCES;
    static const std::string LENGHT;
    static const std::string MAX_TIME_STR;
    static const std::string START_TIME_WINDOW;
    static const std::string END_TIME_WINDOW;
    static const std::string HEADER;
    static const std::string ALLOW_IDLES;
    static const std::string TASK_NAME;
    static const std::string RESOURCE_NAME;
    static const std::string DO_PRECEDENCES;
    static const std::string N_PRECEDENCES;
    static const std::string ARRAY_PRECEDENCES;
    static const std::string DUMMY_MATRIX;

    // Methods.
    // --------

    std::string PrintLenght() const;
    std::string PrintStartTimeWindow() const;
    std::string PrintEndTimeWindow() const;
    std::string PrintResources() const;
    std::string PrintCapacity() const;

    std::size_t Idx( const tStringVector & a_vector, const std::string & a_str );

    template< typename T >
    std::string PrintVector( const std::vector< T > & a_vector ) const;

    // Protect default copy constructor.
    MiniZincCodeGenerator( const MiniZincCodeGenerator & a_other );

    // Protect default operator =.
    MiniZincCodeGenerator & operator = ( const MiniZincCodeGenerator & a_other );

};

template< typename T >
std::string MiniZincCodeGenerator::PrintVector( const std::vector< T > & a_vector ) const
{
    std::ostringstream strStream;

    typename std::vector< T >::const_iterator itBegin = a_vector.begin();
    typename std::vector< T >::const_iterator it      = a_vector.begin();
    typename std::vector< T >::const_iterator itEnd   = a_vector.end();
    while( it != itEnd )
    {
        if( it == itBegin )
            strStream << "[";

        strStream << *it;
        ++it;

        if( it != itEnd )
            strStream << ",";
        else
            strStream << "]";
    }

    return strStream.str();
}

template<>
std::string MiniZincCodeGenerator::PrintVector( const tStringVector & a_vector ) const;

template<>
std::string MiniZincCodeGenerator::PrintVector( const tPrecedencesVector & a_vector ) const;

#endif // MINIZINCCODEGENERATOR_H
